/*********************************************************************************************************************
* seekfree_ch32v203_wireless_charge_opensource_software 即（CH32V203 无线充电开源软件）
* 是一个基于官方 SDK 接口的开源软件
* Copyright (c) 2022 SEEKFREE 逐飞科技
*
* 本文件是 CH32V203 无线充电开源软件的一部分
*
* CH32V203 无线充电开源软件 是免费软件
* 您可以根据自由软件基金会发布的 GPL（GNU General Public License，即 GNU通用公共许可证）的条款
* 即 GPL 的第3版（即 GPL3.0）或（您选择的）任何后来的版本，重新发布和/或修改它
*
* 本开源库的发布是希望它能发挥作用，但并未对其作任何的保证
* 甚至没有隐含的适销性或适合特定用途的保证
* 更多细节请参见 GPL
*
* 您应该在收到本开源库的同时收到一份 GPL 的副本
* 如果没有，请参阅<https://www.gnu.org/licenses/>
*
* 额外注明：
* 本开源库使用 GPL3.0 开源许可证协议 以上许可申明为译文版本
* 许可申明英文版在 libraries/doc 文件夹下的 GPL3_permission_statement.txt 文件中
* 许可证副本在 libraries 文件夹下 即该文件夹下的 LICENSE 文件
* 欢迎各位使用并传播本程序 但修改内容时必须保留逐飞科技的版权声明（即本声明）
*
* 文件名称          zf_common_clock
* 公司名称          成都逐飞科技有限公司
* 版本信息          查看 libraries/doc 文件夹内 version 文件 版本说明
* 开发环境          MDK 5.37
* 适用平台          CH32V203
* 店铺链接          https://seekfree.taobao.com/
*
* 修改记录
* 日期              作者                备注
* 2023-01-04        Teternal            first version
********************************************************************************************************************/

#include "ch32v20x.h"

#include "zf_common_clock.h"

uint32 system_clock = SYSTEM_CLOCK_144M;                                        // 系统时钟信息

//-------------------------------------------------------------------------------------------------------------------
// 函数简介     核心时钟恢复初始设置
// 参数说明     void
// 返回参数     void
// 使用示例     clock_reset();
// 备注信息     本函数在文件内部调用 用户不用关注 也不可修改
//-------------------------------------------------------------------------------------------------------------------
//static void clock_reset (void)
//{
//}
void SystemInit (void)
{
}

//-------------------------------------------------------------------------------------------------------------------
// 函数简介     核心时钟设置
// 参数说明     clock       时钟频率 推荐使用 zf_common_clock.h 中 system_clock_enum 定义的选项
// 返回参数     void
// 使用示例     clock_set_freq(clock);
// 备注信息     本函数在文件内部调用 用户不用关注 也不可修改
//-------------------------------------------------------------------------------------------------------------------
static void clock_set_freq(uint32 clock)
{
    __IO uint32_t timeout_count = 0;

    system_clock = clock;

    RCC->CTLR   |=  0x00000001;
    RCC->CFGR0  &=  0xF0FF0000;

    RCC->CTLR   &=  0xFEF6FFFF;
    RCC->CTLR   &=  0xFFFBFFFF;
    RCC->CFGR0  &=  0xFF80FFFF;
    RCC->INTR   =   0x009F0000;

    RCC->CTLR   |=  RCC_HSEON;

    while((!(RCC->CTLR & RCC_HSERDY)) && (HSE_STARTUP_TIMEOUT > timeout_count ++));

    if(RCC->CTLR & RCC_HSERDY)
    {
        RCC->CFGR0  |=  RCC_HPRE_DIV1;
        RCC->CFGR0  |=  RCC_PPRE2_DIV1;
        RCC->CFGR0  |=  RCC_PPRE1_DIV1;

        RCC->CFGR0  &=  ~( RCC_PLLSRC | RCC_PLLXTPRE | RCC_PLLMULL);
        RCC->CFGR0  |=  (RCC_PLLSRC_HSE | RCC_PLLXTPRE_HSE | ((clock / BOARD_XTAL_FREQ - 2) << 18));

        RCC->CTLR   |=  RCC_PLLON;
        while(0 == (RCC->CTLR & RCC_PLLRDY));

        RCC->CFGR0  &=  ~(RCC_SW);
        RCC->CFGR0  |=  RCC_SW_PLL;
        while(0x08 != (RCC->CFGR0 & RCC_SWS));
    }
    else
    {
        while(1);
    }
}

//-------------------------------------------------------------------------------------------------------------------
// 函数简介     核心时钟初始化
// 参数说明     clock       时钟频率 推荐使用 zf_common_clock.h 中 system_clock_enum 定义的选项
// 返回参数     void
// 使用示例     clock_init(SYSTEM_CLOCK_144M);                                  // 初始化核心时钟为 144MHz
// 备注信息     本函数用于将核心时钟设置到指定频率
//-------------------------------------------------------------------------------------------------------------------
void clock_init(uint32 clock)
{
    clock_set_freq(clock);

    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC2, ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);

    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);

    RCC_ADCCLKConfig(RCC_PCLK2_Div8);
}
